﻿#pragma once

#include <vector>
#include <iostream>
#include <memory>
#include "Serial.h"

struct Header
{
    uint32_t version = 1001;
};
COutputSerializer& operator<<(COutputSerializer& ser, const Header& header);
CInputSerializer& operator>>(CInputSerializer& ser, Header& header);

class Shape: public ISerializable
{
public:
    virtual void Draw() = 0;
};

class ShapeGroup : public Shape
{
public:	
    std::vector<std::shared_ptr<Shape>> m_shapes;
public:
    void Add(const std::shared_ptr<Shape>& shape);

    virtual void Draw() override;

    DECL_SERIAL()
    virtual size_t WriteTo(COutputSerializer& ser) const override;
    virtual size_t ReadFrom(CInputSerializer& ser) override;
};

class Circle : public Shape
{
public:
    virtual void Draw() override
    {
        std::cout << "circle@" << this << std::endl;
    }

    DECL_SERIAL()
    virtual size_t WriteTo(COutputSerializer& ser) const override
    {
        auto begin = ser.Position();
        ser << std::string("Circle");
        return ser.Position() - begin;
    }
    virtual size_t ReadFrom(CInputSerializer& ser) override
    {
        std::string str;
        auto begin = ser.Position();
        ser >> str;
        return ser.Position() - begin;
    }
};

class Rectangle : public Shape
{
    std::string m_newVersion = " # new version";
public:
    virtual void Draw() override
    {
        std::cout << "Rectangle@" << this << m_newVersion << std::endl;
    }

    DECL_SERIAL()
        
    virtual size_t WriteTo(COutputSerializer& ser) const override
    {
        auto begin = ser.Position();
        ser << std::string("Rectangle");
        auto ohser = dynamic_cast<COHSerializer<Header>*>(&ser);
        if (ohser && ohser->Header().version > 100)
        {
            ser << m_newVersion;
        }
        return ser.Position() - begin;
    }

    virtual size_t ReadFrom(CInputSerializer& ser) override
    {
        std::string str;
        auto begin = ser.Position();
        ser >> str;
        auto ihser = dynamic_cast<CIHSerializer<Header>*>(&ser);
        if (ihser && ihser->Header().version > 100)
        {
            ser >> m_newVersion;
        }
        else
        {
            m_newVersion.clear();
        }
        return ser.Position() - begin;
    }
};